/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.cuni.mff.abacs.burglar.logics.objects.items;

import cz.cuni.mff.abacs.burglar.logics.objects.BaseInterface;
import cz.cuni.mff.abacs.burglar.logics.objects.BaseInterface.Type;
import java.util.*;


/**
 *
 * @author abacs
 */
public class InventoryImpl implements Inventory {
	
	
	/**
	 * Items by their identifiers.
	 * 
	 * Changeable property. */
	protected final Map<Integer, Item> _byId = 
		new HashMap<Integer, Item>();
	
	/**
	 * Items by their types.
	 */
	protected final Map<BaseInterface.Type, List<Item>> _byType = 
		new EnumMap<BaseInterface.Type, List<Item>>(BaseInterface.Type.class);
	
	
	// -------------------------------------------------------------------------
	// constructors:
	
	
	/**
	 * 
	 */
	public InventoryImpl() {
		
	}
	
		
	/**
	 * Takes the content of the inventory.
	 * 
	 * @param other
	 */
	protected InventoryImpl(InventoryImpl other) {
		
		// items are not copied. they are static objects
		for(Item item : other._byId.values())
			this._byId.put(item.getId(), item);
		
		for(List<Item> items : other._byType.values()){
			if(items.isEmpty() == false){
				this._byType.put(items.get(0).getType(), new ArrayList<Item>(items));
			}
		}
	}
	
	
	// -------------------------------------------------------------------------
	// Inventory:
	
	
	@Override
	public void addItem(Item item) {
		if(this.hasItem(item.getId()))
			return;
		
		this._byId.put(new Integer(item.getId()), item);
		
		BaseInterface.Type type = item.getType();
		
		if(this._byType.containsKey(type)){
			List<Item> items = this._byType.get(type);
			if(items.contains(item) == false)
				items.add(item);
		}else{
			List<Item> items = new LinkedList<Item>();
			items.add(item);
			this._byType.put(type, items);
		}
	}
	
	
	@Override
	public void addItems(List<Item> items) {
		for(Item item : items){
			if(this.hasItem(item.getId()))
				continue;
			this.addItem(item);
		}
	}
	
	
	@Override
	public Item removeItem(int id) {
		Item ret = this._byId.get(id);
		this._byId.remove(id);
		
		List<Item> typeItems = this._byType.get(ret.getType());
		typeItems.remove(ret);
		
		return ret;
	}
	
	
	
	@Override
	public boolean hasItem(int id) {
		if(this._byId.get(id) != null)
			return true;
		return false;
	}
	
	
	@Override
	public boolean hasItemOfType(Type type) {
		return
			this._byType.containsKey(type) && 
			this._byType.get(type).isEmpty() == false;
	}
	
	
	@Override
	public int getItemIdOfType(Type type) {
		List<Item> items = this._byType.get(type);
		if(items != null && items.isEmpty() == false){
			return items.get(0).getId();
		}
		return -1;
	}
	
	
	@Override
	public List<Item> getItems() {
		List<Item> ret = new ArrayList<Item>();
		for(Item item : this._byId.values()){
			ret.add(item);
		}
		return ret;
	}
	
	
	// -------------------------------------------------------------------------
	
	
	/** Checks whether the object looks identical with another one from far. */
	public boolean matchesFromFar(InventoryImpl inv) {
		return true;
	}
	
	
	/**  Checks whether the object looks identical with another one from nearby. */
	public boolean matchesFromClose(InventoryImpl inv) {
		if(this._byId.size() != inv._byId.size())
			return false;
		
		for(int itemId : this._byId.keySet())
			if(inv.hasItem(itemId) == false)
				return false;
		
		return true;
	}
	
	/**
	 * Copies the properties of the other object.
	 * 
	 * @param original 
	 */
	public void copyChangeables(InventoryImpl original) {
						
		this._byId.clear();
		this._byType.clear();
		for(Item item : original._byId.values()){
			this.addItem(item);
		}
	}
	
	
	/**
	 * Creates a copy of itself.
	 * 
	 * @return 
	 */
	public InventoryImpl copy() {
		return new InventoryImpl(this);
	}
	
	
}

